﻿using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using AutoMapper;
using Helper.Attributes;

namespace API.Helpers
{
    public static class EntityFrameworkHelper
    {
        public static T BuildEmptyEntityForAttachment<T>(T entity, Type baseEmptyEntityOnType)
            where T : new()
        {
            var result = new T();
            if (baseEmptyEntityOnType == null)
                return result;
            var modelMembers = baseEmptyEntityOnType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var memberInfo in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (modelMembers.Where(m => m.Name.ToUpper() == memberInfo.Name.ToUpper()).Count() > 0)
                {
                    var modelMemberInfo = modelMembers.Where(m => m.Name.ToUpper() == memberInfo.Name.ToUpper()).FirstOrDefault();
                    bool ignore = modelMemberInfo.GetCustomAttributes(typeof(IgnoreForAttachmentAttribute), true).Count() > 0 && ((IgnoreForAttachmentAttribute)modelMemberInfo.GetCustomAttributes(typeof(IgnoreForAttachmentAttribute), true).First()).IgnoreForMethod != IgnoreForMethod.Add;
                    if (!ignore)
                    {
                        if (memberInfo.PropertyType == typeof(Guid) || (memberInfo.PropertyType.IsGenericType && memberInfo.PropertyType.GetGenericArguments()[0] == typeof(Guid)))
                            memberInfo.SetValue(result, Guid.Parse("{FFFFFFFE-FFFE-FFFE-FFFE-FFFFFFFFFFFE}"), new object[] { });
                        if (memberInfo.PropertyType == typeof(String))
                            memberInfo.SetValue(result, "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZY", new object[] { });
                        if (memberInfo.PropertyType == typeof(int) || memberInfo.PropertyType == typeof(int?))
                            memberInfo.SetValue(result, Int32.MinValue + 1, new object[] { });
                        if (memberInfo.PropertyType == typeof(decimal))
                            memberInfo.SetValue(result, decimal.MinValue + 1, new object[] { });
                        if (memberInfo.PropertyType == typeof(float))
                            memberInfo.SetValue(result, float.MinValue + 1, new object[] { });
                        if (memberInfo.PropertyType == typeof(DateTime))
                            memberInfo.SetValue(result, DateTime.MinValue.AddDays(1), new object[] { });
                        if (memberInfo.PropertyType == typeof(bool))
                            memberInfo.SetValue(result, !(bool)memberInfo.GetValue(entity, new object[] { }), new object[] { });
                    }
                    else
                    {
                        memberInfo.SetValue(result, memberInfo.GetValue(entity, new object[] { }), new object[] { });
                    }
                }
            }
            return result;
        }


        //TODO: Need to get cloning working on object;
        public static T ResetEntityForAdd<T>(T entity, Type baseEmptyEntityOnType)
           where T : new()
        {
            Mapper.CreateMap<T, T>();
            var result = entity.DeepClone();//Mapper.Map<T>(entity);
            if (baseEmptyEntityOnType == null)
                return result;
            var modelMembers = baseEmptyEntityOnType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var memberInfo in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {

                if (modelMembers.Where(m => m.Name == memberInfo.Name).Count() > 0)
                {
                    var modelMemberInfo = modelMembers.Where(m => m.Name == memberInfo.Name).FirstOrDefault();
                    bool ignore = modelMemberInfo.GetCustomAttributes(typeof(IgnoreForAttachmentAttribute), true).Count() > 0 && ((IgnoreForAttachmentAttribute)modelMemberInfo.GetCustomAttributes(typeof(IgnoreForAttachmentAttribute), true).First()).IgnoreForMethod != IgnoreForMethod.Update;
                    if (ignore) memberInfo.SetValue(result, Activator.CreateInstance(memberInfo.PropertyType), new object[] { });
                }
            }
            return result;
        }

        private static T DeepClone<T>(this T a)
        {
            using (var stream = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(stream, a);
                stream.Position = 0;
                return (T)formatter.Deserialize(stream);
            }

        }
    }
}